require("luaText")
require('exportLuaEnum')
require('exportLuaType')
function getDumpFunctions(f,ffunc)
    local functions = {};
    local len = 0;
    if(f)then len = #f;end;
    for k,v in ipairs(function_decl)do
        local func = v:GetDecl();
        local src,line = func:GetFilePosition();
        if(dumpSourceFlag and dumpSource[src])then
            table.insert(functions,func);
        elseif(f==nil and ffunc==nil)then
            table.insert(functions,func);
        elseif(f==nil)then
            if(dumpSourceFlag)then
            else
                table.insert(functions,func);
            end
        else
            local name = func.name.strg;
            if(name==nil)then name = "";end;
            if(f == name:sub(1,len) or ffunc(name,v))then
                table.insert(functions,func);
            end
        end
    end

    table.sort(functions,function(a,b)
        local an = a.name.strg;
        local bn = b.name.strg;
        --print(an,bn);
        if(an==nil)then return false;end;
        if(bn==nil)then return false;end;
        return an<bn;
    end
    );
    return functions;
end

typeTable = {
    ['int'] = 'luaL_checkinteger',
    ['void*' ] = 'lcheck_toptr',
    ['float' ] = 'luaL_checknumber',
    ['double'] = 'luaL_checknumber',
};

retPushTable = {
    ['int'] = 'lua_pushinteger(L,ret);',
    ['void*'] = 'lua_pushlightuserdata(L,ret);',
    ['float'] = 'lua_pushnumber(L,ret);',
    ['double'] = 'lua_pushnumber(L,ret);',
};

function GetToLuaType(type,ref)
    local typeName;
    if(ref==nil)then ref = 0;end;
    if(ref>0)then
        typeName = "void*"
    elseif(type:IsIntegerType() or type:IsEnumType())then typeName = "int"
    elseif(type:IsRealType())then typeName = 'double'
    elseif(type:IsRecordType())then noout = true;
    elseif(type:IsVoid())then typeName = "void";
    elseif(type:IsPointerType())then typeName="void*";
    elseif(type:IsBoolType())then typeName = 'int';
    else
        print('==================================',type.id,type.code);
        assert(false);
    end
    return typeName;
end

function dumpFunctions2lua(f,out)
    local dumpAll = false;
    local len;
    local dump_list = {};

    if(out==nil)then out = io.stderr;
    elseif(type(out)=='string')then out = io.open(out,'w+');end;
    local functions = getDumpFunctions(f,isDump);

    local funcNames = {};
    WriteHead(out);
    if(cpp2cfunc)then
        out:write('typedef (*cfunc)(...);\n');
        for k,v in ipairs(functions)do
            local f = v:GetFunction();
            if(f.name)then 
                local s = string.format('#define %s ((cfunc)&%s)\n',f.name,f.name);
                out:write(s);
            end
        end
        out:write('\n\n\n');
    end

    for k,v in ipairs(functions)do
        local f = v:GetFunction();
        if(f.name and Remove[f.name]~=nil)then
            out:write(string.format("\n//remove function %s\n\n\n",f.name));
        end
        if(f.name and Remove[f.name]==nil)then
            table.insert(funcNames,f.name);
            local noCall = false;
            local arg_num = 0;
            --out:write(f.name .. ":");
            local s = string.format('static int l%s(lua_State*L){\n',f.name);
            out:write(s);
            for kk,vv in ipairs(f.args)do
                arg_num = arg_num + 1;
                --local name = vv.
                local type,name,ref = vv:GetParmInfo();
                local typeName = "";
                local noout = false;
                --print(ref);
                if(type:IsRefType())then
                    typeName = nil;
                else
                    typeName = GetToLuaType(type,ref);
                end

                if(typeName)then
                    local s = "  %s a%d = (%s)%s(L,%d);\n";
                    s = string.format(s,typeName,kk,typeName,typeTable[typeName],kk);
                    out:write(s.."");
                else
                    --RecordType
                    noCall = true;
                end
            end
            --print(f.retn.id);
            local retType;
            retType = GetToLuaType(f.retn);
            if(noCall)then
                --不调用
                out:write(string.format('  const char*err = "error c func call:%s";\n',f.name));
                out:write('  luaL_error(L,err);\n');
            else
                local s;
                local retS = "";
                local retPush = "";
                local args = '';
                local comma = '';
                for idx=1,arg_num do
                    args = args .. string.format("%sa%d",comma,idx);
                    comma = ','
                end
                if(retType==nil or retType=="void")then
                else 
                    retS = "%s ret = (%s)"
                    retS = string.format(retS,retType,retType);
                    retPush = '  '..retPushTable[retType]..'\n';
                end;
                s = '  %s%s(%s);\n%s'
                s = string.format(s,retS,f.name,args,retPush)
                out:write(s);
                if(retS~='')then
                    out:write('  return 1;\n');
                else
                    out:write('  return 0;\n');
                end
            end
            out:write('}\n\n');
        end
    end

    local libName = lib_name;
    if(libName==nil)then  libName = 'test';end;

    local openLibName = string.format('int %s_openlibs(lua_State*L)',libName);
    local luaopenName = string.format('int luaopen_%s(lua_State*L)',libName);
    local extenC = [[
#if defined(__cplusplus)
extern "C"{
#endif

%s; //openlibs
%s; //luaopen 

#if defined(__cplusplus)
}
#endif

]];
    out:write(string.format(extenC,openLibName,luaopenName));
    if(typeExport)then
        exportType(f,out);
    end
    out:write(openLibName..'{\n');
    WriteDefine(out,libName);
    out:write(string.format('  //export Lua functions:%d\n\n',#funcNames));
    for kk=1,#funcNames do
        local s = string.format('  lregister(L,%s);\n',funcNames[kk]);
        out:write(s);
    end
    out:write('  lTypeInit(L);\n')
    exportEnum(f,out);
    
    out:write('  return 0;\n};\n\n');
    out:write(string.format(luaopenName..'{\n  return %s_openlibs(L);\n};\n\n',libName));

end


